package com.nsoft.html5npub.utils;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.webkit.WebView;
import android.widget.ImageButton;

import com.nsoft.html5npub.R;
import com.nsoft.html5npub.business.dbengine;
import com.nsoft.html5npub.objects.BitmapPage;
import com.nsoft.html5npub.objects.BookItem;
import com.nsoft.html5npub.objects.BookmarkItem;
import com.nsoft.html5npub.objects.ChapterInfo;
import com.nsoft.html5npub.objects.PageInfo;
import com.nsoft.html5npub.objects.ViewEngineListener;
import com.nsoft.html5npub.objects.PageVideo;
import com.nsoft.html5npub.objects.ViewEngineListener.EventData;

/**
 * <b>viewengine</b> supports functionality to open a book
 * and other functions
 * 
 * @author minhld
 *
 */
public class viewengine {
	/**
	private static final int PAGE_LOAD_PROGRESS_DONE=99;
	*/
	private static SortedMap<Integer,ChapterInfo> 
			chapList=new TreeMap<Integer,ChapterInfo>();
	
	/**
	private static Map<BookCoord,BookmarkItem> 
		bookmarkList=new HashMap<BookCoord,BookmarkItem>();
	*/
	private static Map<String,BookmarkItem> bookmarkList=
				new HashMap<String,BookmarkItem>();
	
	/**
	private static Map<String,ArrayList<String>> 
		javascriptList=new HashMap<String, ArrayList<String>>();
	*/
	
	private static BookItem currentBook;
	private static String bookPath;
	private static ViewEngineListener viewListener;
	
	public static BookItem getCurrentBook() {
		return currentBook;
	}
	public static void setCurrentBook(
					BookItem currentBook) {
		viewengine.currentBook = currentBook;
	}
	
	public static String getCurrentBookPath(){
		return viewengine.bookPath;
	}
	
	public static void setViewEngineListener(
				ViewEngineListener _viewListener){
		viewengine.viewListener=_viewListener;
	}
	
	/**
	 * find index of page indicated by <i>pageId</i><br>
	 * it will returns -1 if no item was found
	 * 
	 * @param pageId
	 * @return
	 */
	public static int findPageIndex(String pageId){
		int index=0;
		for (ChapterInfo cInf:chapList.values()){
			for (PageInfo[] vertPageList:cInf.get2DPageList()){
				if (vertPageList!=null){
					for (int k=0;k<vertPageList.length;k++){
						if (vertPageList[k].getId().
								equalsIgnoreCase(pageId)){
							return index;
						}
						index++;
					}
				}
			}
		}
		return -1;
	}
	
	public static PageInfo findPage(String pageId){
		PageInfo retPage=null;
		PageInfo[][] page2DList;
		PageInfo[] vertPageList;
		for (ChapterInfo cInf:chapList.values()){
			page2DList=cInf.get2DPageList();
			for (int i=0;i<page2DList.length;i++){
				vertPageList=page2DList[i];
				if (vertPageList!=null){
					for (int j=0;j<vertPageList.length;
							j++){
						if (vertPageList[j].getId().
									equals(pageId)){
							retPage=vertPageList[j];
							break;
						}
					}
				}
				if (retPage!=null)
					break;
			}
			if (retPage!=null)
				break;
		}
		return retPage;
	}
	
	/**
	 * get list of chapter in a collection
	 * @return
	 */
	public static Collection<ChapterInfo> getChapterList(){
		return viewengine.chapList.values();
	}
	
	public static List<PageInfo[]> getVerticalPageList(){
		List<PageInfo[]> vertPageList=
					new ArrayList<PageInfo[]>();
		PageInfo[][] page2DList;
		for (ChapterInfo cInf:viewengine.chapList.values()){
			page2DList=cInf.get2DPageList();
			for (int i=0;i<page2DList.length;i++){
				vertPageList.add(page2DList[i]);
			}
		}
		return vertPageList;
	}
	
	public static View[] createViews(Context context,
						ViewGroup parent){
		ArrayList<View> viewList=new ArrayList<View>();
		ChapterInfo[] chaps=chapList.values().
					toArray(new ChapterInfo[]{});
		
		View view=null;
		PageInfo[][] page2DList;
		PageInfo[] vertPageList;
		/**
		String fileUrl=Constant.EMPTY,
			pageId=Constant.EMPTY;
		*/
		int count=0;
		for (int i=0;i<chaps.length;i++){
			page2DList=chaps[i].get2DPageList();
			for (int j=0;j<page2DList.length;j++){
				vertPageList=page2DList[j];
				if (vertPageList!=null){
					for (int k=0;k<vertPageList.length;k++){
						/**
						fileUrl=Constant.URL_PREFIX+
								vertPageList[k].getPath();
						pageId=vertPageList[k].getId();
						*/
						view=createPageView(context,parent,
								vertPageList[k],count,
								i<=1&&j<=1&&k<=1);
						
						view.setTag(vertPageList[k].getId());
						viewList.add(view);						
						count++;
						
						/**
						fileUrl=Constant.URL_PREFIX+
							vertPageList[k].getPath();
						view=createWebView(
								context,parent,fileUrl);
						viewList.add(view);
						*/
					}
					
					
					/**
					if (vertPageList.length==1){
						view=createWebView(context);
						((WebView)view).loadUrl(
							Constant.URL_PREFIX+
							vertPageList[0].getPath());
					}else{
						view=new ViewFlipper(context);
					}
					*/
					
				}
			}
		}
		
		return viewList.toArray(new View[]{});
	}
	
	/** @SuppressWarnings("deprecation") */
	@SuppressLint("SetJavaScriptEnabled")
	private static View createPageView(Context ctx,
			ViewGroup parent,PageInfo pageInfo,
			int viewIdx,boolean isRenderHighPriority){
		
		String fileUrl=Constant.URL_PREFIX+
							pageInfo.getPath();
		String pageId=pageInfo.getId();
		
		LayoutInflater inflater=(LayoutInflater)ctx.
				getSystemService(Context.
						LAYOUT_INFLATER_SERVICE);
		
		View view=inflater.inflate(
				R.layout.page_view,parent,false);
		
		ExWebView wv=(ExWebView)view.findViewById(
								R.id.webviewPage);
		wv.setParentView(view);
		
		/**
		WebSettings settings=wv.getSettings();
		settings.setAllowFileAccess(true);
		settings.setLoadWithOverviewMode(true);
		settings.setUseWideViewPort(true);
		settings.setBuiltInZoomControls(true);
		settings.setJavaScriptEnabled(true);
		settings.setPluginsEnabled(true);
		if (isRenderHighPriority){
			settings.setRenderPriority(RenderPriority.HIGH);
		}else{
			settings.setRenderPriority(RenderPriority.LOW);
		}
		
		wv.setWebChromeClient(new WebChromeClient(){
			@Override
			public boolean onConsoleMessage(
					ConsoleMessage consoleMessage) {
				Log.e("viewengine.createWebView()",
						consoleMessage.toString());
				return true;
			}
		});
		*/
		
		/**
		String[] jsList=javascriptList.get(pageId).
						toArray(new String[]{});
		wv.setWebViewClient(new ExWebViewClient(jsList));
		*/
		
		/**
		wv.setWebViewClient(new ExWebViewClient());
		
		wv.setHorizontalScrollBarEnabled(false);
		wv.setVerticalScrollBarEnabled(false);
		*/
		
		wv.setInitialScale(getScale(ctx,wv));
		
		/**
		if (Build.VERSION.SDK_INT>=
				Build.VERSION_CODES.HONEYCOMB){
			settings.setDisplayZoomControls(false);
		}
		
		wv.setBackgroundColor(Color.BLACK);
		*/
		
		ImageButton bookmarkIconBtn=(ImageButton)view.
        		findViewById(R.id.bookmarkIconButton);
        bookmarkIconBtn.setOnClickListener(new 
        		BookmarkIconClickListener(view,pageId));
        /**
        BookmarkItem bmItem=bookmarkList.get(
    					new BookCoord(viewIdx,0));
    	*/
        BookmarkItem bmItem=bookmarkList.get(pageId);
        bookmarkIconBtn.setVisibility(bmItem!=null?
        					View.VISIBLE:View.GONE);
		
		wv.loadUrl(fileUrl);
		
		/**
		if (pageInfo.getPageVideo()!=null){
			loadVideo(ctx,view,pageInfo);
		}
		*/
		
		return view;
	}
	
	/**
	private static void loadVideo(Context c,
						View v,PageInfo pageInfo){
		PageVideo pageVideo=pageInfo.getPageVideo();
		
		String pagePath=pageInfo.getPath();
		int endOffs=pagePath.lastIndexOf("/")+1;
		String parentFolderPath=pagePath.substring(0,endOffs);
		String videoPath=parentFolderPath+
						pageVideo.getFilePath();
		
		FrameLayout vidContainer=new FrameLayout(c);
		vidContainer.setLayoutParams(new FrameLayout.
				LayoutParams(pageVideo.getWidth(),
							pageVideo.getHeight()));
		MaskVideoView videoView=new MaskVideoView(c);

		vidContainer.setPadding(pageVideo.getPosX(),
							pageVideo.getPosY(),0,0);
		vidContainer.addView(videoView);
		((RelativeLayout)v).addView(vidContainer);
		
		videoView.setVideoPath(videoPath);
	}
	*/
	
	static class BookmarkIconClickListener implements 
							View.OnClickListener{
		private View currentView;
		private String pageId=Constant.EMPTY;
		
		public BookmarkIconClickListener(
						View currView,String _pageId){
			this.currentView=currView;
			this.pageId=_pageId;
		}
		
		@Override
		public void onClick(View v) {
			if (this.pageId==null ||
					this.pageId.equals(Constant.EMPTY))
				return;
			deleteBookmark(pageId);
			ImageButton bookmarkIconBtn=(ImageButton)
					currentView.findViewById(
							R.id.bookmarkIconButton);
	    	bookmarkIconBtn.setVisibility(View.GONE);
		}
	}
	
	/**
	@SuppressWarnings("deprecation")
	@SuppressLint("SetJavaScriptEnabled")
	private static View createWebView(Context ctx,
					ViewGroup parent,String fileUrl){
		LayoutInflater inflater=(LayoutInflater)
				ctx.getSystemService(
					Context.LAYOUT_INFLATER_SERVICE);
		
		View view=inflater.inflate(
				R.layout.page_view,parent,false);
		
		WebView wv=(WebView)view.
				findViewById(R.id.webviewPage);
		WebSettings settings=wv.getSettings();
		settings.setAllowFileAccess(true);
		settings.setLoadWithOverviewMode(true);
		settings.setUseWideViewPort(true);
		settings.setBuiltInZoomControls(true);
		settings.setJavaScriptEnabled(true);
		settings.setPluginsEnabled(true);
		settings.setRenderPriority(RenderPriority.HIGH);
		
		
		wv.setHorizontalScrollBarEnabled(false);
		wv.setVerticalScrollBarEnabled(false);
		
		wv.setInitialScale(getScale(ctx,wv));
		if (Build.VERSION.SDK_INT>=
				Build.VERSION_CODES.HONEYCOMB){
			settings.setDisplayZoomControls(false);
		}
		
		final ProgressBar progressor=(ProgressBar)view.
				findViewById(R.id.progressbarPageLoad);
		progressor.setVisibility(View.VISIBLE);
		
		wv.setWebChromeClient(new WebChromeClient(){
			@Override
			public boolean onConsoleMessage(
					ConsoleMessage consoleMessage) {
				
				Log.e("viewengine.createWebView()",
						consoleMessage.sourceId()+","+
						consoleMessage.lineNumber()+": "+
						consoleMessage.message());
				return super.onConsoleMessage(consoleMessage);
			}
			
			@Override
			public void onProgressChanged(WebView view,
						int newProgress) {
				if (newProgress<PAGE_LOAD_PROGRESS_DONE){
					progressor.setProgress(newProgress);
				}else if (newProgress>=PAGE_LOAD_PROGRESS_DONE){
					progressor.setVisibility(View.GONE);
				}
			}
			
			
		});
		
		wv.setWebViewClient(new ExWebViewClient());
		
		wv.loadUrl(fileUrl);
		
		return view;
	}
	*/
	
	public static List<BitmapPage> getBookmarkPages(){
		List<BitmapPage> pageList=new 
					ArrayList<BitmapPage>();
		BookmarkItem bmItem;
		PageInfo pInfo;
		String bmpPath;
		Bitmap bmp;
		for (String pageId:bookmarkList.keySet()){
			bmItem=bookmarkList.get(pageId);
			pInfo=findPage(bmItem.getPageId());
			if (pInfo!=null){
				bmpPath=bookPath+Constant.PATH_SPLITTER+
						pInfo.getChapterName()+
						Constant.PATH_SPLITTER+
						Constant.CHR_SMALLSIZE_REMARK+
						pInfo.getName();
				try {
					bmp=utils.createBitmap(bmpPath);
					pageList.add(new BitmapPage(bmp,pInfo));
				}catch(IOException e){
					Log.e("viewengine.getBookmarkPages()",
						e.getClass()+": "+e.getMessage());
				}
			}
		}
		return pageList;
	}
	
	public static List<Bitmap> getDelegatePages(){
		ChapterInfo[] chaps=chapList.values().
						toArray(new ChapterInfo[]{});
		
		List<Bitmap> bmpList=new ArrayList<Bitmap>();
		
		PageInfo[][] page2DList;
		PageInfo[] vertPageList;
		String bmpPath;
		Bitmap bmp;
		for (int i=0;i<chaps.length;i++){
			page2DList=chaps[i].get2DPageList();
			for (int j=0;j<page2DList.length;j++){
				vertPageList=page2DList[j];
				if (vertPageList!=null&&vertPageList.length>0){
					bmpPath=bookPath+Constant.PATH_SPLITTER+
							vertPageList[0].getChapterName()+
							Constant.PATH_SPLITTER+
							Constant.CHR_SMALLSIZE_REMARK+
							vertPageList[0].getName();
					try{
						bmp=utils.createBitmap(bmpPath);
						bmpList.add(bmp);
					}catch(IOException e){
						Log.e("viewengine.getDelegatePages()",
								e.getClass()+": "+e.getMessage());
					}
				}
			}
		}
		return bmpList;
	}
	
	/**
	 * remove all attached data in array before leaving
	 * the view screen
	 */
	public static void removeBeforeQuit(){
		chapList.clear();
		chapList=null;
		bookmarkList.clear();
		bookmarkList=null;
	}
	
	public static void cleanUp(){
		chapList=new TreeMap<Integer,ChapterInfo>();
		chapList.clear();
		/**
		javascriptList=new HashMap<String,ArrayList<String>>();
		javascriptList.clear();
		*/
		/**
		bookmarkList=new HashMap<BookCoord,BookmarkItem>();
		*/
		bookmarkList=new HashMap<String,BookmarkItem>();
		bookmarkList.clear();
	}
	
	public static void getBookmarkList(){
		bookmarkList.clear();
		bookmarkList=dbengine.getBookmarkMap(
				currentBook.getContentId());
	}
	
	public static void addBookmark(String pageId,
					int pageIndexX,int pageIndexY){
		BookmarkItem bmItem=new BookmarkItem();
		bmItem.setContentId(currentBook.getContentId());
		bmItem.setPageId(pageId);
		bmItem.setPageIndexX(pageIndexX);
		bmItem.setPageIndexY(pageIndexY);
		dbengine.addBookmark(bmItem);
		/**
		viewengine.bookmarkList.put(new 
				BookCoord(pageIndexX,pageIndexY),
				bmItem);
		*/
		viewengine.bookmarkList.put(pageId,bmItem);
	}
	
	public static void deleteBookmark(String pageId
				/**int pageIndexX,int pageIndexY*/){
		BookmarkItem bmItem=new BookmarkItem();
		bmItem.setContentId(currentBook.getContentId());
		bmItem.setPageId(pageId);
		/**
		bmItem.setPageIndexX(pageIndexX);
		bmItem.setPageIndexY(pageIndexY);
		*/
		dbengine.deleteBookmark(bmItem);
		/**
		viewengine.bookmarkList.remove(new 
				BookCoord(pageIndexX,pageIndexY));
		*/
		viewengine.bookmarkList.remove(pageId);
	}
	
	public static boolean isBookmarkExist(
				String pageId
				/**int pageIndexX,int pageIndexY*/){
		return bookmarkList.containsKey(pageId);
	}
		
	public static void getBookFromBookConfig(
						String configFilePath){
	
		bookPath=configFilePath.substring(0,configFilePath.
						lastIndexOf(Constant.PATH_SPLITTER));
		cleanUp();
		
		DisplayMetrics dm=utils.getDeviceMetrics();
		float scaledDensity=dm!=null?dm.scaledDensity:
						Constant.DEFAULT_SCALED_DENSITY;
		
		try{
			DocumentBuilderFactory docBuilderFactory=
						DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder=docBuilderFactory.
								newDocumentBuilder();
			FileInputStream fis=new 
					FileInputStream(configFilePath);
			Document doc=docBuilder.parse(fis);
			
			NodeList list=doc.getElementsByTagName(
						Constant.xml.XML_CONFIG_TAG_PAGE);
		
			NodeList c_nodes=null; 
			ChapterInfo chInfo=null;
			int chapIndex=-1;
			PageInfo pInfo=null;
			String nodeCont=Constant.EMPTY,nodeName;
			boolean isPageGotBugs=false;
			for (int i=0;i<list.getLength();i++){
				c_nodes=list.item(i).getChildNodes();
				pInfo=new PageInfo();
				isPageGotBugs=false;
				
				for (int j=0;j<c_nodes.getLength();j++){
					nodeCont=c_nodes.item(j).getTextContent();
					nodeName=c_nodes.item(j).getNodeName();
					
					if (nodeName==null||
						nodeName.trim().equals(Constant.EMPTY)||
						nodeName.startsWith(Constant.CHR_SHARP)){
						continue;	/* skip if tag is unknown */
					}
					
					if (nodeName.equalsIgnoreCase(
						Constant.xml.XML_CONFIG_TAG_PAGEID)){
						if (nodeCont.equals(Constant.EMPTY)){
							isPageGotBugs=true;
							break;
						}
						pInfo.setId(nodeCont);
					}else if (nodeName.equalsIgnoreCase(
						Constant.xml.XML_CONFIG_TAG_PAGEINDEX)){
						if (nodeCont.equals(Constant.EMPTY)){
							isPageGotBugs=true;
							break;
						}
						chapIndex=Integer.parseInt(
								nodeCont.substring(0,2))-1;
						pInfo.setChapter(chapIndex);
						pInfo.setChapterName(
								nodeCont.substring(0,2));
						pInfo.sethIndex(Integer.parseInt(
								nodeCont.substring(2,4))-1);
						pInfo.setvIndex(Integer.parseInt(
								nodeCont.substring(4,5))-1);
					}else if (nodeName.equalsIgnoreCase(
						Constant.xml.XML_CONFIG_TAG_PAGENAME)){
						if (nodeCont.equals(Constant.EMPTY)){
							isPageGotBugs=true;
							break;
						}
						pInfo.setName(nodeCont);
					}else if (nodeName.equalsIgnoreCase(
						Constant.xml.XML_CONFIG_TAG_VIDEO)){
						NodeList videoNodes=c_nodes.item(j).
												getChildNodes();
						if (videoNodes.getLength()==0)
							continue;
						PageVideo video=new PageVideo();
						for (int k=0;k<videoNodes.getLength();k++){
							nodeCont=videoNodes.item(k).getTextContent();
							nodeName=videoNodes.item(k).getNodeName();
							
							if (nodeName==null||
								nodeName.trim().equals(Constant.EMPTY)||
								nodeName.startsWith(Constant.CHR_SHARP)){
								continue;	/* skip if tag is unknown */
							}
							
							if (nodeName.equalsIgnoreCase(
									Constant.xml.XML_CFTAG_AUTOPLAY)){
								video.setAutoPlay(nodeCont);
							}else if (nodeName.equalsIgnoreCase(
								Constant.xml.XML_CFTAG_WIDTH)){
								/**
								int w=(int)((float)Integer.
									parseInt(nodeCont)/scaledDensity);
								*/
								int w=Integer.parseInt(nodeCont);
								video.setWidth(w);
							}else if (nodeName.equalsIgnoreCase(
								Constant.xml.XML_CFTAG_HEIGHT)){
								
								int h=(int)((float)Integer.
									parseInt(nodeCont)/scaledDensity);
								/**
								int h=Integer.parseInt(nodeCont);
								*/
								video.setHeight(h);
							}else if (nodeName.equalsIgnoreCase(
								Constant.xml.XML_CFTAG_X)){
								int left=(int)((float)Integer.
										parseInt(nodeCont)/scaledDensity);
								video.setPosX(left);
							}else if (nodeName.equalsIgnoreCase(
								Constant.xml.XML_CFTAG_Y)){
								int top=(int)((float)Integer.
										parseInt(nodeCont)/scaledDensity);
								video.setPosY(top);
							}else if (nodeName.equalsIgnoreCase(
								Constant.xml.XML_CFTAG_FILENAME)){
								video.setFilePath(nodeCont);
							}
						}
						pInfo.setPageVideo(video);
					}
				}
				if (!isPageGotBugs){
					pInfo.autoSetPath(bookPath);
					if (!chapList.containsKey(chapIndex)){
						chInfo=new ChapterInfo(chapIndex);
						chapList.put(chInfo.getId(),chInfo);
					}else{
						chInfo=chapList.get(chapIndex);
					}
					/**
					getJsList(pInfo.getId(),pInfo.getPath());
					*/
					chInfo.addPage(pInfo);
				}
			}
			
			fis.close();
		}catch(Exception e){
			Log.e("engine.getPageFromConfigFile()",
				e.getClass()+": "+e.getMessage());
		}
	}
	
	/**
	private static void getJsList(String pageId,
			String htmlPagePath) throws Exception {
		
		int offs=htmlPagePath.lastIndexOf(Constant.PATH_DOT);
		String jsListFile=htmlPagePath.substring(0,offs+1)+
									Constant.STR_XML;
				
		try{
			DocumentBuilderFactory docBuilderFactory=
						DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder=docBuilderFactory.
									newDocumentBuilder();
			FileInputStream fis=new 
					FileInputStream(jsListFile);
			Document doc=docBuilder.parse(fis);
			
			NodeList list=doc.getElementsByTagName(
						Constant.utils.XML_JSFILE);
			ArrayList<String> jsList=new ArrayList<String>();
			String jsFile=Constant.EMPTY;
			for (int i=0;i<list.getLength();i++){
				jsFile=list.item(i).getTextContent();
				jsList.add(jsFile);
			}
			javascriptList.put(pageId,jsList);
			
			fis.close();
		}catch(Exception e){
			throw e;
		}
	}
	*/
	
	/**
	 * open an arbitrary page from 2-dimension page list<br>
	 * it will find out the proper index of the page in the 
	 * single dimension page list
	 * 
	 * @param page
	 */
	public static void openPage(PageInfo page){
		EventData e=new EventData();
		int pageIndex=findPageIndex(page.getId());
		e.pageIndexX=pageIndex;
		viewengine.viewListener.eventFired(e);
	}
	
	public static void openBookmarkPage(PageInfo pInfo){
		EventData e=new EventData();
		BookmarkItem bmItem=viewengine.
				bookmarkList.get(pInfo.getId());
		if (bmItem!=null){
			e.pageIndexX=bmItem.getPageIndexX();
			viewengine.viewListener.eventFired(e);
		}
	}
	
	private static int getScale(Context ctx,WebView wv){
		Display display = ((WindowManager)ctx.
	    	getSystemService(Context.
	    		WINDOW_SERVICE)).getDefaultDisplay(); 
		@SuppressWarnings("deprecation")
		int width = display.getWidth(); 
	    Double val = (double)width/
	    		(double)Constant.pagesize.WIDTH;
	    val = val * 100d;
	    return val.intValue();
	}

}
